<!-- 实体关系探索组件 - 威胁目标关联信号溯源 -->
<template>
  <div class="entity-relation-explorer">
    <div class="explorer-header">
      <h3 class="section-title">
        <el-icon><Share /></el-icon>
        实体关系探索
      </h3>
      <div class="header-actions">
        <el-button-group size="small">
          <el-button @click="resetView">
            <el-icon><Refresh /></el-icon>
            重置视图
          </el-button>
          <el-button @click="exportGraph">
            <el-icon><Download /></el-icon>
            导出图谱
          </el-button>
          <el-button type="primary" @click="startTracing">
            <el-icon><Connection /></el-icon>
            开始溯源
          </el-button>
        </el-button-group>
      </div>
    </div>

    <div class="explorer-content">
      <!-- 3D关系图谱展示区 -->
      <div class="graph-container">
        <div ref="graphContainer" class="d3-graph"></div>
        
        <!-- 图谱控制面板 -->
        <div class="graph-controls">
          <div class="control-group">
            <label>关系类型:</label>
            <el-select v-model="selectedRelationType" size="small" @change="filterByRelation">
              <el-option label="全部关系" value="all"></el-option>
              <el-option label="威胁关联" value="threat"></el-option>
              <el-option label="信号溯源" value="signal"></el-option>
              <el-option label="时间关联" value="temporal"></el-option>
              <el-option label="空间关联" value="spatial"></el-option>
            </el-select>
          </div>
          
          <div class="control-group">
            <label>节点深度:</label>
            <el-slider
              v-model="nodeDepth"
              :min="1"
              :max="5"
              :step="1"
              size="small"
              @change="updateDepth"
            ></el-slider>
          </div>
          
          <div class="control-group">
            <label>显示标签:</label>
            <el-switch v-model="showLabels" @change="toggleLabels"></el-switch>
          </div>
        </div>
      </div>

      <!-- 实体详情面板 -->
      <div class="entity-details" v-if="selectedEntity">
        <div class="detail-header">
          <h4>{{ selectedEntity.name }}</h4>
          <el-tag :type="getEntityTypeColor(selectedEntity.type)" size="small">
            {{ selectedEntity.type }}
          </el-tag>
        </div>
        
        <div class="detail-content">
          <div class="detail-item">
            <span class="label">实体ID:</span>
            <span class="value">{{ selectedEntity.id }}</span>
          </div>
          <div class="detail-item">
            <span class="label">威胁级别:</span>
            <el-rate
              v-model="selectedEntity.threatLevel"
              disabled
              show-score
              text-color="#ff9900"
            ></el-rate>
          </div>
          <div class="detail-item">
            <span class="label">关联信号:</span>
            <div class="signal-list">
              <el-tag
                v-for="signal in selectedEntity.signals"
                :key="signal.id"
                size="small"
                class="signal-tag"
                @click="traceSignal(signal)"
              >
                {{ signal.frequency }}MHz
              </el-tag>
            </div>
          </div>
          <div class="detail-item">
            <span class="label">时空坐标:</span>
            <span class="value">{{ formatCoordinates(selectedEntity.coordinates) }}</span>
          </div>
        </div>
      </div>
    </div>

    <!-- 溯源路径展示 -->
    <div class="trace-path" v-if="tracingPath.length > 0">
      <h4>信号溯源路径</h4>
      <div class="path-timeline">
        <div
          v-for="(step, index) in tracingPath"
          :key="index"
          class="path-step"
          :class="{ active: index === currentStep }"
        >
          <div class="step-number">{{ index + 1 }}</div>
          <div class="step-content">
            <div class="step-title">{{ step.entity }}</div>
            <div class="step-desc">{{ step.description }}</div>
            <div class="step-time">{{ step.timestamp }}</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import * as d3 from 'd3'

// 响应式数据
const graphContainer = ref(null)
const selectedEntity = ref(null)
const selectedRelationType = ref('all')
const nodeDepth = ref(3)
const showLabels = ref(true)
const tracingPath = ref([])
const currentStep = ref(0)

// 模拟数据
const mockEntities = ref([
  {
    id: 'entity_001',
    name: '雷达站A',
    type: '侦察设备',
    threatLevel: 4,
    coordinates: { lat: 39.9042, lng: 116.4074 },
    signals: [
      { id: 'sig_001', frequency: 1200, type: 'radar' },
      { id: 'sig_002', frequency: 1850, type: 'comm' }
    ]
  },
  {
    id: 'entity_002',
    name: '通信中继',
    type: '通信设备',
    threatLevel: 3,
    coordinates: { lat: 39.9142, lng: 116.4174 },
    signals: [
      { id: 'sig_003', frequency: 2400, type: 'comm' },
      { id: 'sig_004', frequency: 5800, type: 'data' }
    ]
  }
])

const mockRelations = ref([
  {
    source: 'entity_001',
    target: 'entity_002',
    type: 'signal',
    strength: 0.8,
    label: '信号关联'
  }
])

// 初始化图谱
const initGraph = () => {
  if (!graphContainer.value) return

  const width = graphContainer.value.clientWidth
  const height = graphContainer.value.clientHeight

  // 清除现有内容
  d3.select(graphContainer.value).selectAll('*').remove()

  const svg = d3.select(graphContainer.value)
    .append('svg')
    .attr('width', width)
    .attr('height', height)

  // 创建力导向图
  const simulation = d3.forceSimulation(mockEntities.value)
    .force('link', d3.forceLink(mockRelations.value).id(d => d.id).distance(100))
    .force('charge', d3.forceManyBody().strength(-300))
    .force('center', d3.forceCenter(width / 2, height / 2))

  // 绘制连接线
  const links = svg.append('g')
    .selectAll('line')
    .data(mockRelations.value)
    .enter().append('line')
    .attr('stroke', '#999')
    .attr('stroke-opacity', 0.6)
    .attr('stroke-width', d => Math.sqrt(d.strength * 5))

  // 绘制节点
  const nodes = svg.append('g')
    .selectAll('circle')
    .data(mockEntities.value)
    .enter().append('circle')
    .attr('r', 15)
    .attr('fill', d => getNodeColor(d.type))
    .call(d3.drag()
      .on('start', dragstarted)
      .on('drag', dragged)
      .on('end', dragended))
    .on('click', (event, d) => {
      selectedEntity.value = d
    })

  // 添加标签
  if (showLabels.value) {
    const labels = svg.append('g')
      .selectAll('text')
      .data(mockEntities.value)
      .enter().append('text')
      .text(d => d.name)
      .attr('font-size', '12px')
      .attr('dx', 20)
      .attr('dy', 5)
  }

  // 更新位置
  simulation.on('tick', () => {
    links
      .attr('x1', d => d.source.x)
      .attr('y1', d => d.source.y)
      .attr('x2', d => d.target.x)
      .attr('y2', d => d.target.y)

    nodes
      .attr('cx', d => d.x)
      .attr('cy', d => d.y)

    svg.selectAll('text')
      .attr('x', d => d.x)
      .attr('y', d => d.y)
  })

  function dragstarted(event, d) {
    if (!event.active) simulation.alphaTarget(0.3).restart()
    d.fx = d.x
    d.fy = d.y
  }

  function dragged(event, d) {
    d.fx = event.x
    d.fy = event.y
  }

  function dragended(event, d) {
    if (!event.active) simulation.alphaTarget(0)
    d.fx = null
    d.fy = null
  }
}

// 获取节点颜色
const getNodeColor = (type) => {
  const colors = {
    '侦察设备': '#ff6b6b',
    '通信设备': '#4ecdc4',
    '干扰设备': '#45b7d1',
    '目标实体': '#f9ca24'
  }
  return colors[type] || '#95a5a6'
}

// 获取实体类型颜色
const getEntityTypeColor = (type) => {
  const typeColors = {
    '侦察设备': 'danger',
    '通信设备': 'success',
    '干扰设备': 'primary',
    '目标实体': 'warning'
  }
  return typeColors[type] || 'info'
}

// 格式化坐标
const formatCoordinates = (coords) => {
  return `${coords.lat.toFixed(4)}°N, ${coords.lng.toFixed(4)}°E`
}

// 重置视图
const resetView = () => {
  initGraph()
  selectedEntity.value = null
  ElMessage.success('视图已重置')
}

// 导出图谱
const exportGraph = () => {
  ElMessage.success('图谱导出功能开发中...')
}

// 开始溯源
const startTracing = () => {
  if (!selectedEntity.value) {
    ElMessage.warning('请先选择一个实体节点')
    return
  }
  
  // 模拟溯源路径
  tracingPath.value = [
    {
      entity: '雷达站A',
      description: '检测到1200MHz雷达信号',
      timestamp: '2024-01-15 14:30:25'
    },
    {
      entity: '信号中继',
      description: '信号经过中继站转发',
      timestamp: '2024-01-15 14:30:28'
    },
    {
      entity: '目标源头',
      description: '定位到信号源头位置',
      timestamp: '2024-01-15 14:30:32'
    }
  ]
  currentStep.value = 0
  ElMessage.success('开始信号溯源分析')
}

// 按关系类型过滤
const filterByRelation = (type) => {
  // 重新绘制图谱
  initGraph()
}

// 更新深度
const updateDepth = (depth) => {
  // 重新计算显示深度
  initGraph()
}

// 切换标签显示
const toggleLabels = (show) => {
  initGraph()
}

// 追踪信号
const traceSignal = (signal) => {
  ElMessage.info(`正在追踪信号: ${signal.frequency}MHz`)
}

// 组件挂载后初始化
onMounted(() => {
  nextTick(() => {
    initGraph()
  })
})
</script>

<style scoped>
.entity-relation-explorer {
  height: 100%;
  display: flex;
  flex-direction: column;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 1vh;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.explorer-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 2vh 3vw;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.section-title {
  color: #ffffff;
  font-size: 1.8rem;
  margin: 0;
  display: flex;
  align-items: center;
  gap: 1vw;
}

.explorer-content {
  flex: 1;
  display: flex;
  padding: 2vh 3vw;
  gap: 2vw;
}

.graph-container {
  flex: 2;
  position: relative;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 1vh;
  overflow: hidden;
}

.d3-graph {
  width: 100%;
  height: 40vh;
}

.graph-controls {
  position: absolute;
  top: 2vh;
  right: 2vw;
  background: rgba(0, 0, 0, 0.7);
  padding: 1.5vh 2vw;
  border-radius: 0.8vh;
  backdrop-filter: blur(10px);
  min-width: 15vw;
}

.control-group {
  margin-bottom: 1.5vh;
}

.control-group label {
  display: block;
  color: #ffffff;
  font-size: 0.9rem;
  margin-bottom: 0.5vh;
}

.entity-details {
  flex: 1;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 1vh;
  padding: 2vh;
  max-height: 40vh;
  overflow-y: auto;
}

.detail-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 2vh;
  padding-bottom: 1vh;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.detail-header h4 {
  color: #ffffff;
  margin: 0;
  font-size: 1.2rem;
}

.detail-content {
  color: #ffffff;
}

.detail-item {
  margin-bottom: 1.5vh;
}

.detail-item .label {
  display: inline-block;
  width: 6vw;
  color: #bdc3c7;
  font-size: 0.9rem;
}

.detail-item .value {
  color: #ffffff;
  font-weight: 500;
}

.signal-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5vw;
  margin-top: 0.5vh;
}

.signal-tag {
  cursor: pointer;
  transition: all 0.3s ease;
}

.signal-tag:hover {
  transform: scale(1.05);
}

.trace-path {
  padding: 2vh 3vw;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(0, 0, 0, 0.2);
}

.trace-path h4 {
  color: #ffffff;
  margin-bottom: 2vh;
  font-size: 1.2rem;
}

.path-timeline {
  display: flex;
  gap: 2vw;
  overflow-x: auto;
  padding-bottom: 1vh;
}

.path-step {
  min-width: 15vw;
  display: flex;
  align-items: center;
  gap: 1vw;
  padding: 1.5vh 2vw;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 0.8vh;
  border: 1px solid rgba(255, 255, 255, 0.1);
  transition: all 0.3s ease;
}

.path-step.active {
  background: rgba(74, 144, 226, 0.2);
  border-color: #4a90e2;
  transform: scale(1.02);
}

.step-number {
  width: 3vh;
  height: 3vh;
  border-radius: 50%;
  background: #4a90e2;
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 0.9rem;
}

.step-content {
  flex: 1;
}

.step-title {
  color: #ffffff;
  font-weight: 500;
  margin-bottom: 0.5vh;
}

.step-desc {
  color: #bdc3c7;
  font-size: 0.8rem;
  margin-bottom: 0.5vh;
}

.step-time {
  color: #95a5a6;
  font-size: 0.7rem;
}

/* 深色主题滚动条 */
::-webkit-scrollbar {
  width: 0.5vw;
}

::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 0.25vw;
}

::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.3);
  border-radius: 0.25vw;
}

::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.5);
}
</style>